﻿using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using BusinessBingo.Web.Controllers;
using BusinessBingo.Web.Infrastructure.InfoStores.Interfaces;
using Castle.Core;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;

namespace BusinessBingo.Web.Infrastructure
{
    /// <summary>
    /// WindsorInstaller for Web project
    /// </summary>
    public class WebInstaller : IWindsorInstaller
    {
        private LifestyleType _lifestyleType;

        /// <summary>
        /// Ctor with given lifestyletype. 
        /// </summary>
        /// <param name="lifestyleType">The lifestyleType will be configured for all infrastructure. Controllers needs to be Transient.</param>
        public WebInstaller(LifestyleType lifestyleType)
        {
            this._lifestyleType = lifestyleType;
        }

        /// <summary>
        /// Register Web componentes in container
        /// </summary>
        /// <param name="container">IoC Container where compontents are registered</param>
        /// <param name="store">IoC Store for configuration </param>
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            this.InstallControllers(container);
            this.InstallInfrastructure(container);
        }

        /// <summary>
        /// Register each controller
        /// </summary>
        /// <param name="container"></param>
        private void InstallControllers(IWindsorContainer container)
        {
            var controllerTypes =
                 from t in typeof(HomeController).Assembly.GetTypes()
                 where typeof(IController).IsAssignableFrom(t)
                 select t;

            // workaround http://stackoverflow.com/questions/2784846/castle-windsor-controller-factory-and-renderaction
            foreach (Type t in controllerTypes)
                container.Register(Component.For(t).LifeStyle.Is(LifestyleType.Transient).Named(t.FullName));
        }

        /// <summary>
        /// Register (web) infrastructure
        /// </summary>
        /// <param name="container"></param>
        private void InstallInfrastructure(IWindsorContainer container)
        {
            container.Register(AllTypes.FromAssembly(typeof (ICookieRepository).Assembly).
                                   Pick().
                                   WithService.
                                   FirstInterface().Configure(x => x.LifeStyle.Is(this._lifestyleType)));

            // for integrationtests with the IoC configuration - HttpContext would always be null
            // just plug a mock into the container for unit testing
            if (HttpContext.Current != null)
            { 
                container.Register(Component.For<HttpContextBase>()
                                      .LifeStyle.Is(this._lifestyleType)
                                      .UsingFactoryMethod(() => new HttpContextWrapper(HttpContext.Current)));

                container.Register(Component.For<HttpRequestBase>()
                      .LifeStyle.Is(this._lifestyleType)
                      .UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request)));
            }
        }
    }
}